package br.ufrj.xml.util;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;

import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

public class XmlToJtree extends JPanel
{
	private static Document document; 

    private static final int windowHeight = 460;
    private static final int leftWidth = 300;
    private static final int rightWidth = 340;
    private static final int windowWidth = leftWidth + rightWidth;

	private static final String[] typeName = {
        "none",
        "Element",
        "Attr",
        "Text",
        "CDATA",
        "EntityRef",
        "Entity",
        "ProcInstr",
        "Comment",
        "Document",
        "DocType",
        "DocFragment",
        "Notation",
    };
	
    public XmlToJtree(){
    	super();
    	//initialize();
    }
    
    public XmlToJtree(Document theDocument){
    	super();
    	this.document = theDocument;
    	initialize();
    }

    private void initialize() {

    	EmptyBorder eb = new EmptyBorder(5,5,5,5);
        BevelBorder bb = new BevelBorder(BevelBorder.LOWERED);
        CompoundBorder cb = new CompoundBorder(eb,bb);
        this.setBorder(new CompoundBorder(cb,eb));

        JTree tree = new JTree(new DomToTreeModelAdapter());

        JScrollPane treeView = new JScrollPane(tree);
        treeView.setPreferredSize( new Dimension( leftWidth, windowHeight ));

        JEditorPane htmlPane = new JEditorPane("text/html","");
        htmlPane.setEditable(false);
        JScrollPane htmlView = new JScrollPane(htmlPane);
        htmlView.setPreferredSize( new Dimension( rightWidth, windowHeight ));

        JSplitPane splitPane = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT,treeView,htmlView );
        splitPane.setContinuousLayout( true );
        splitPane.setDividerLocation( leftWidth );
        splitPane.setPreferredSize( new Dimension( windowWidth + 10, windowHeight+10 ));

        this.setLayout(new BorderLayout());
        this.add("Center", splitPane );
	}

    public class AdapterNode{ 
    	
      Node domNode;

      public AdapterNode(Node node) {
    	  domNode = node;
      }

      public String toString() {
        String s = typeName[domNode.getNodeType()];
        String nodeName = domNode.getNodeName();
        if (! nodeName.startsWith("#")) {
           s += ": " + nodeName;
        }
        if (domNode.getNodeValue() != null) {
           if (s.startsWith("ProcInstr")) 
              s += ", "; 
           else 
              s += ": ";
           
           String t = domNode.getNodeValue().trim();
           int x = t.indexOf("\n");
           if (x >= 0) t = t.substring(0, x);
           s += t;
        }
        return s;
      }

      public int index(AdapterNode child) {
        int count = childCount();
        for (int i=0; i<count; i++) {
          AdapterNode n = this.child(i);
          if (child.domNode == n.domNode) 
        	  return i;
        }
        return -1; 
      }

      public AdapterNode child(int searchIndex) {
        Node node = domNode.getChildNodes().item(searchIndex);
        return new AdapterNode(node); 
      }

      public int childCount() {
          return domNode.getChildNodes().getLength();  
      }
    }

    public class DomToTreeModelAdapter implements TreeModel{
    	
    	private Vector listenerList = new Vector();
		
    	public Object  getRoot() {
    		return new AdapterNode(document);
    	}
      
    	public boolean isLeaf(Object aNode) {
    		AdapterNode node = (AdapterNode) aNode;
    		if (node.childCount() > 0) 
    			return false;
    		return true;
    	}
    	
		public int getChildCount(Object parent) {
			AdapterNode node = (AdapterNode) parent;
			return node.childCount();
		}
		
		public Object getChild(Object parent, int index) {
			AdapterNode node = (AdapterNode) parent;
			return node.child(index);
		}
		
		public int getIndexOfChild(Object parent, Object child) {
			AdapterNode node = (AdapterNode) parent;
			return node.index((AdapterNode) child);
		}
		  
		public void valueForPathChanged(TreePath path, Object newValue) {
		}

		public void addTreeModelListener(TreeModelListener listener) {
			if ( listener != null && ! listenerList.contains( listener ) ) {
				listenerList.addElement( listener );
			}
		}
      
		public void removeTreeModelListener(TreeModelListener listener) {
			if ( listener != null ) {
				listenerList.removeElement( listener );
			}
		}

		public void fireTreeNodesChanged( TreeModelEvent e ) {
			Enumeration listeners = listenerList.elements();
			while ( listeners.hasMoreElements() ) {
				TreeModelListener listener = (TreeModelListener) listeners.nextElement();
				listener.treeNodesChanged( e );
			}
		} 
		
		public void fireTreeNodesInserted( TreeModelEvent e ) {
			Enumeration listeners = listenerList.elements();
			while ( listeners.hasMoreElements() ) {
				TreeModelListener listener = (TreeModelListener) listeners.nextElement();
				listener.treeNodesInserted( e );
			}
		}   
		
		public void fireTreeNodesRemoved( TreeModelEvent e ) {
			Enumeration listeners = listenerList.elements();
			while ( listeners.hasMoreElements() ) {
				TreeModelListener listener = (TreeModelListener) listeners.nextElement();
				listener.treeNodesRemoved( e );
			}
		} 
  
		public void fireTreeStructureChanged( TreeModelEvent e ) {
			Enumeration listeners = listenerList.elements();
			while ( listeners.hasMoreElements() ) {
				TreeModelListener listener = (TreeModelListener) listeners.nextElement();
				listener.treeStructureChanged( e );
			}
		}
    }
    
    public static void main(String argv[])
    {
    	DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        //factory.setValidating(true);   
        //factory.setNamespaceAware(true);
        
    	try 
    	{
           DocumentBuilder builder = factory.newDocumentBuilder();
           document = builder.parse( new File("pedido4\\pedido4.xml") );
			
           JFrame frame = new JFrame("DOM Echo");
			frame.addWindowListener(
			  new WindowAdapter() {
			    public void windowClosing(WindowEvent e) {System.exit(0);}
			  }  
			);
			
			XmlToJtree echoPanel = new XmlToJtree();
			frame.getContentPane().add("Center", echoPanel );
			frame.pack();
			
			Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
			int w = windowWidth + 10;
			int h = windowHeight + 10;
			
			frame.setLocation(screenSize.width/3 - w/2, screenSize.height/2 - h/2);
			frame.setSize(w, h);
			frame.setVisible(true);
 
        } catch (SAXException sxe) {
           // Error generated during parsing)
           Exception  x = sxe;
           if (sxe.getException() != null)
               x = sxe.getException();
           x.printStackTrace();

        } catch (ParserConfigurationException pce) {
            // Parser with specified options can't be built
            pce.printStackTrace();

        } catch (IOException ioe) {
           // I/O error
           ioe.printStackTrace();
        }
    } 

}
